import neo4j from 'neo4j-driver';
import * as d3 from 'd3'
import {ElMessage, ElMessageBox} from "element-plus";
const driver = neo4j.driver('bolt://localhost:7687', neo4j.auth.basic('neo4j', '13579Fsz'));
// 添加驱动状态检查
let isDriverClosed = false;
export async function getData() {
    const session = driver.session();
    try {
        if (isDriverClosed) {
            ElMessage.error("节点数据库已经关闭了！！！");
            throw new Error("Neo4j driver is already closed");
        }
        const result = await session.run('MATCH (n)-[r]->(m) RETURN n, r, m');
        // 处理数据，提取节点和关系
        const nodes = [];
        const links = [];
        const nodeMap = {};

        result.records.forEach(record => {
            const sourceNode = record.get('n');
            const targetNode = record.get('m');
            const relationship = record.get('r');

            if (!nodeMap[sourceNode.identity.low]) {
                const node = {
                    id: sourceNode.identity.low,
                    label: sourceNode.properties.name,
                    x: 0,
                    y: 0
                };
                nodes.push(node);
                nodeMap[sourceNode.identity.low] = node;
            }
            if (!nodeMap[targetNode.identity.low]) {
                const node = {
                    id: targetNode.identity.low,
                    label: targetNode.properties.name,
                    x: 0,
                    y: 0
                };
                nodes.push(node);
                nodeMap[targetNode.identity.low] = node;
            }

            // 处理关系
            const link = {
                source: sourceNode.identity.low,
                target: targetNode.identity.low,
                relationship: relationship.properties.description
            };
            links.push(link);
        });
        console.log(nodes);
        console.log(links);
        return { nodes, links };
    } finally {
        await session.close();
    }
}
export const renderGraph = async () => {
    const data = await getData();
    const nodes = data.nodes;
    const links = data.links;

    const container = document.getElementById('graph-container');
    if (!container) return;
    // 动态获取容器尺寸
    const width = container.clientWidth;
    const height = container.clientHeight;
    console.log('Container size:', width, height);
    // 清除旧 SVG
    d3.select("#graph-container").html("");

    // 创建新 SVG
    const svg = d3.select("#graph-container")
        .append("svg")
        .attr("width", width)
        .attr("height", height)
        .attr("viewBox", `0 0 ${width} ${height}`); // 关键：设置 viewBox

    const simulation = d3.forceSimulation(nodes)
        .force("link", d3.forceLink(links).id(d => d.id).strength(0.1)) // 增强链接强度
        .force("charge", d3.forceManyBody().strength(-650)) // 增强斥力
        .force("collide", d3.forceCollide(20)) // 添加防重叠
        // 修改后（添加动态调整）
        .force("center", d3.forceCenter(width / 2, height / 2))
        .force("x", d3.forceX(width / 2).strength(0.1))  // 添加横向约束
        .force("y", d3.forceY(height / 2).strength(0.1)) // 添加纵向约束
        .alphaDecay(0.0228) // 保持默认冷却速度
        .alpha(1) // 重启模拟
        .restart();

// 添加模拟完成检测
    simulation.on("end", () => {
        console.log("布局稳定");
    });
    // 颜色比例尺
    const colorScale = d3.scaleOrdinal(d3.schemeCategory10);

    // 边渐变定义
    const gradient = svg.append("defs")
        .append("linearGradient")
        .attr("id", "linkGradient")
        .attr("gradientTransform", "rotate(45)")
        .selectAll("stop")
        .data(["#888", "#ccc"])
        .enter().append("stop")
        .attr("offset", (d, i) => i * 50 + "%")
        .attr("stop-color", d => d);

    const link = svg
      .append("g")
      .attr("stroke", "#666")
      .attr("stroke-opacity", 0.8)
      .selectAll("line")
      .data(links)
      .join("line")
      .attr("stroke-width", (d) => Math.sqrt(d.relationship.length || 1) + 1)
      .attr("marker-end", "url(#arrowhead)") // 添加箭头引用
      .on("click", (event, d) => {
          // 高亮逻辑
          d3.selectAll("line").style("opacity", 0.2);
          d3.select(event.target).style("opacity", 1);
          svg.selectAll("circle").style("fill", d => colorScale(d.id));
          d3.select(`#node-${d.source.id}`).style("fill", "#FF6B6B");
          d3.select(`#node-${d.target.id}`).style("fill", "#4ECDC4");
          ElMessageBox.alert(d.relationship, '节点之间的关系', {
              confirmButtonText: 'OK',
              callback: () => {
                  ElMessage({
                      type: 'info',
                      message: `action: 关闭消息窗口`,
                  })
              },
          })
      });

    // 添加箭头标记
    svg.append("defs").append("marker")
        .attr("id", "arrowhead")
        .attr("viewBox", "-0 -5 10 10")
        .attr("refX", 15)
        .attr("refY", 0)
        .attr("orient", "auto")
        .attr("markerWidth", 1.65)
        .attr("markerHeight", 1.65)
        .append("path")
        .attr("d", "M0,-5 L10,0 L0,5")
        .attr("fill", "red");

    const node = svg.append("g")
        .attr("stroke", "#fff")
        .attr("stroke-width", 1.5)
        .selectAll("circle")
        .data(nodes)
        .join("circle")
        .attr("id", d => `node-${d.id}`) // 添加唯一id
        .attr("r", 5)
        .call(drag(simulation));

    const text = svg.append("g")
        .attr("class", "labels")
        .selectAll("text")
        .data(nodes)
        .join("text")
        .text(d => d.label)
        .attr("transform", d => `translate(${d.x},${d.y})`)
        .attr("dx", 8)
        .attr("dy", 3)

    simulation.on("tick", () => {
        link
            .attr("x1", d => d.source.x)
            .attr("y1", d => d.source.y)
            .attr("x2", d => d.target.x)
            .attr("y2", d => d.target.y);

        node
            .attr("cx", d => d.x)
            .attr("cy", d => d.y);

        text
            .attr("x", d => d.x + 8)
            .attr("y", d => d.y + 3);
    });
}
/*// 使用 async/await 调用 getData 函数
(async () => {
    try {
        const data = await getData();
        await renderGraph();
        console.log(data);
    } catch (error) {
        console.error('Error:', error);
    } finally {
        await driver.close();
    }
})();*/
// 添加关闭驱动的方法
export const closeDriver = async () => {
    if (!isDriverClosed) {
        await driver.close();
        isDriverClosed = true;
    }
}
function drag(simulation) {
    // 定义 dragstarted 函数，当节点拖拽开始时触发
    function dragstarted(event) {
        // 如果事件处于非活跃状态，将模拟的 alpha 目标值设置为 0.3 并重启模拟
        // alpha 控制模拟的活跃度，值越大模拟变化越快
        if (!event.active) simulation.alphaTarget(0.3).restart();
        // 将节点的固定 x 坐标设置为当前节点的 x 坐标
        event.subject.fx = event.subject.x;
        // 将节点的固定 y 坐标设置为当前节点的 y 坐标
        event.subject.fy = event.subject.y;
    }

    // 定义 dragged 函数，当节点正在被拖动时触发
    function dragged(event) {
        // 将节点的固定 x 坐标设置为当前鼠标的 x 坐标
        event.subject.fx = event.x;
        // 将节点的固定 y 坐标设置为当前鼠标的 y 坐标
        event.subject.fy = event.y;
    }

    // 定义 dragended 函数，当节点拖拽结束时触发
    function dragended(event) {
        // 如果事件处于非活跃状态，将模拟的 alpha 目标值设置为 0
        if (!event.active) simulation.alphaTarget(0);
        // 取消节点的固定 x 坐标，使节点可以继续参与模拟
        event.subject.fx = null;
        // 取消节点的固定 y 坐标，使节点可以继续参与模拟
        event.subject.fy = null;
    }

    // 创建一个 D3 的拖拽行为对象，并绑定三个事件处理函数
    return d3.drag()
        .on("start", dragstarted)
        .on("drag", dragged)
        .on("end", dragended);
}